package com.gt.wxpay.cashier.common.scheduled;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gt.wxpay.cashier.common.LocalTimeUtils;
import com.gt.wxpay.cashier.domain.PageParameter;
import com.gt.wxpay.cashier.domain.Result;
import com.gt.wxpay.cashier.domain.dto.QueryOrderDto;
import com.gt.wxpay.cashier.domain.dto.QueryRefundDto;
import com.gt.wxpay.cashier.domain.model.CashierPayment;
import com.gt.wxpay.cashier.domain.model.PaymentStatusEnum;
import com.gt.wxpay.cashier.domain.model.RefundStatusEnum;
import com.gt.wxpay.cashier.domain.model.TransactionTypeEnum;
import com.gt.wxpay.cashier.notifyRecord.application.NotifyRecordService;
import com.gt.wxpay.cashier.payment.application.PaymentService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * packageName com.gt.wxpay.cashier.common.schdule
 *
 * @author GuoTong
 * @version JDK 8
 * @className OrderStatusUpdateSchdule
 * @date 2024/3/20
 * @description 订单状态--更新
 */
@Service
public class OrderStatusUpdateScheduled {
    private Logger logger = LoggerFactory.getLogger(OrderStatusUpdateScheduled.class);

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private NotifyRecordService notifyRecordService;

    private static List<Integer> whereIn = new ArrayList<>();

    static {
        whereIn.add(PaymentStatusEnum.UNPAY.code());
        whereIn.add(PaymentStatusEnum.PAYING.code());
        whereIn.add(RefundStatusEnum.PROCESSING.getCode());
    }

    @Autowired
    TaskExecutor taskExecutor;

    /**
     * 定时去执行---订单表超过三十分钟的未完成订单-定时关闭
     *
     * @param param param
     * @return ReturnT
     */
    public Result<String> timeOutCLoseOrder(String param) {
        // 默认每页限制条数
        Integer pageSize = 50;
        // 默认通知的最小时间：订单不超过五秒的就暂时搁置
        if (StringUtils.isBlank(param)) {
            JSONObject jsonObject = JSONObject.parseObject(param);
            pageSize = jsonObject.getInteger("pageSize");
        }
        // 当前服务器索引
        int shardIndex = 0;//XxlJobContext.getXxlJobContext().getShardIndex();
        // 总服务器数
        int shardTotal = 1;//XxlJobContext.getXxlJobContext().getShardTotal();
        try {
            // 获取当前这天--需要定时更新的订单
            String TimeOutValue = LocalTimeUtils.getBeforeThirtyMinutes();
            // 分页参数
            PageParameter pageParameter = new PageParameter();
            // 本次任务需要处理的数据等于默认分页大小*调度任务服务器数量
            pageParameter.setPageSize(pageSize * shardTotal);
            pageParameter.setCurrentPage(1);
            IPage<CashierPayment> page = new Page<>(pageParameter.getCurrentPage(), pageParameter.getPageSize());
            // 查询当天订单既没有成功也没有失败的订单--定时更新
            List<CashierPayment> list = paymentService.listNeedCloseOrderByPage(TimeOutValue, whereIn, page);
            if (CollectionUtils.isEmpty(list)) {
                return Result.success();
            }
            for (CashierPayment payment : list) {
                if (shardIndex != (payment.getMid() % shardTotal)) {
                    continue;
                }
                if (payment.getTransactionType().intValue() == TransactionTypeEnum.PAY.code()) {
                    // 触发关闭订单业务逻辑
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("paymentNo", payment.getPaymentNo());
                    jsonObject.put("paymentTime", LocalTimeUtils.getCurrentTime());
                    jsonObject.put("amount", payment.getAmount());
                    jsonObject.put("payStatus", PaymentStatusEnum.CLOSED.code());
                    try {
                        Result<String> result = paymentService.closeOrder(payment.getPaymentNo());
                        jsonObject.put("payStatusDesc", result.isSuccess() ? "订单已关闭" : "微信侧关闭失败,收银台执行关闭");
                    } catch (Exception e) {
                        logger.error("关闭微信侧支付订单失败" + e.getMessage());
                        // 防止已支付的订单被错误执行关闭----二次回归校验
                        if (e.getMessage().contains("该订单已支付")) {
                            jsonObject.put("payStatusDesc", "订单已支付");
                            payment.setStatus(PaymentStatusEnum.PAYED.code());
                            payment.setChannelReturnMessage(PaymentStatusEnum.PAYED.name());
                        } else {
                            jsonObject.put("payStatusDesc", "微信侧关闭异常:" + e.getMessage() + ",收银台执行关闭");
                            payment.setStatus(PaymentStatusEnum.CLOSED.code());
                            payment.setChannelReturnMessage(PaymentStatusEnum.CLOSED.name());
                        }
                        logger.info("关闭微信侧支付订单失败--进入丢弃微信侧订单,本地执行支付订单关闭Success,等待微信侧自动关闭");
                    }
                    jsonObject.put("paySuccessTime", null);
                    // 更新订单信息
                    paymentService.updateById(payment);
                    // 发送支付订单超时---通知
                    taskExecutor.execute(() -> {
                        notifyRecordService.sendMqSuccessPayCallBackMsg(payment.getNotifyUrl(), jsonObject);
                    });
                }
                if (payment.getTransactionType().intValue() == TransactionTypeEnum.REFUND.code()) {
                    QueryRefundDto refundDto = new QueryRefundDto();
                    refundDto.setAmount(payment.getAmount());
                    refundDto.setRefundAmount(payment.getRefundAmount());
                    refundDto.setCreateTime(payment.getCreateTime());
                    refundDto.setRefundTime(null);
                    refundDto.setRefundNo(payment.getPaymentNo());
                    refundDto.setStatus(RefundStatusEnum.CLOSED.getCode());
                    try {
                        Result<String> result = paymentService.closeOrder(payment.getPaymentNo());
                        logger.info(result.isSuccess() ? "订单已关闭" : "微信侧关闭失败,收银台执行关闭");
                    } catch (Exception e) {
                        logger.error("关闭微信侧退款订单失败" + e.getMessage());
                        // 防止已支付的订单被错误执行关闭----二次回归校验
                        if (e.getMessage().contains("该订单已退款")) {
                            payment.setStatus(RefundStatusEnum.SUCCESS.getCode());
                            refundDto.setStatus(RefundStatusEnum.SUCCESS.getCode());
                            payment.setChannelReturnMessage(PaymentStatusEnum.PAYED.name());
                        } else {
                            payment.setStatus(PaymentStatusEnum.CLOSED.code());
                            payment.setChannelReturnMessage(PaymentStatusEnum.CLOSED.name());
                        }
                        logger.info("关闭微信侧退款订单失败--进入丢弃微信侧订单,本地执行支付订单关闭Success,等待微信侧自动关闭");
                    }
                    // 更新订单信息
                    paymentService.updateById(payment);
                    // 发送支付订单超时---通知
                    taskExecutor.execute(() -> {
                        notifyRecordService.sendSuccessRefundCallBackMsg(payment.getNotifyUrl(), refundDto);
                    });
                }
            }
        } catch (Exception e) {
            logger.error("订单表当天的订单结果查询更新--定时任务执行失败", e);
            return Result.error("失败");
        }
        return Result.success();
    }

    /**
     * 定时去执行---订单表三十分钟内未完成的订单结果查询更新
     *
     * @param param param
     * @return ReturnT
     */
    public Result<String> updateOrderStatus(String param) {
        // 默认每页限制条数
        Integer pageSize = 50;
        // 默认通知的最小时间：订单不超过五秒的就暂时搁置
        Integer notifyMinTimeBySeconds = 10;
        if (StringUtils.isBlank(param)) {
            JSONObject jsonObject = JSONObject.parseObject(param);
            pageSize = jsonObject.getInteger("pageSize");
            notifyMinTimeBySeconds = jsonObject.getInteger("notifyMinTimeBySeconds");
        }
        // 当前服务器索引
        int shardIndex = 0;//XxlJobContext.getXxlJobContext().getShardIndex();
        // 总服务器数
        int shardTotal =1;//XxlJobContext.getXxlJobContext().getShardTotal();

        try {
            // 获取当前这天--需要定时更新的订单
            String currentTime = LocalTimeUtils.getBeforeThatSeconds(notifyMinTimeBySeconds);
            String TimeOutValue = LocalTimeUtils.getBeforeThirtyMinutes();
            // 分页参数
            PageParameter pageParameter = new PageParameter();
            // 本次任务需要处理的数据等于默认分页大小*调度任务服务器数量
            pageParameter.setPageSize(pageSize * shardTotal);
            pageParameter.setCurrentPage(1);
            IPage<CashierPayment> page = new Page<>(pageParameter.getCurrentPage(), pageParameter.getPageSize());
            // 查询当天订单既没有成功也没有失败的订单--定时更新
            List<CashierPayment> list = paymentService.listNotEndingOrderByPage(currentTime, TimeOutValue, whereIn, page);
            if (CollectionUtils.isEmpty(list)) {
                return Result.success();
            }
            for (CashierPayment payment : list) {
                if (shardIndex != (payment.getMid() % shardTotal)) {
                    continue;
                }
                if (payment.getTransactionType().intValue() == TransactionTypeEnum.PAY.code()) {
                    // 查询付款
                    QueryOrderDto queryOrderDto = paymentService.queryInfo(payment.getPaymentNo());
                    if (whereIn.contains(queryOrderDto.getPayStatus())) {
                        // 状态未发生变化
                        continue;
                    }
                    // 更新业务侧--消息推送
                    String jsonString = JSONObject.toJSONString(queryOrderDto);
                    JSONObject jsonObject = JSONObject.parseObject(jsonString);
                    jsonObject.put("notifyTime", LocalTimeUtils.getCurrentTime());
                    taskExecutor.execute(() -> {
                        notifyRecordService.sendMqSuccessPayCallBackMsg(payment.getNotifyUrl(), jsonObject);
                    });
                }
                if (payment.getTransactionType().intValue() == TransactionTypeEnum.REFUND.code()) {
                    // 查询退款
                    QueryRefundDto refundDto = paymentService.queryRefund(payment);
                    if (whereIn.contains(refundDto.getStatus())) {
                        // 状态未发生变化
                        continue;
                    }
                    // 更新业务侧
                    taskExecutor.execute(() -> {
                        notifyRecordService.sendSuccessRefundCallBackMsg(payment.getNotifyUrl(), refundDto);
                    });
                }
            }
        } catch (Exception e) {
            logger.error("订单表当天的订单结果查询更新--定时任务执行失败", e);
            return Result.error("失败");
        }
        return Result.success();
    }
}
